package main;

//- IMPORT SECTION .........................................................................................
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;
import java.util.TimeZone;
import java.util.Vector;
import java.util.logging.*;
import org.xml.sax.*;
import org.xml.sax.XMLReader;

import org.htmlparser.sax.*;
import org.htmlparser.filters.*;
import org.xml.sax.SAXException;

import plug.eve.markettracking.model.TrackEntry;
import plug.eve.markettracking.parser.EVEMarketDataParser;

public class MarketHistoryApp extends CommandLineApp {
	private static Logger						logger					= Logger.getLogger("main.MarketHistoryApp");
	private static final String			APPLICATIONNAME	= "MarketHistoryApp";
	private static final int				NOMODULE				= 100;
	private static final int				NOCONFIG				= 1;
	/** Reference to the static part of the application */
	private static MarketHistoryApp	singleton;
	static {
		MarketHistoryApp.logger.setLevel(Level.OFF);
	}
	/**
	 * List of market entries from the HTML page parser. It contains the list of entries that match the list of
	 * stations determined by the future configuration file, but the list for a single module. The program
	 * iterates through the modules and each time this list is cleared.
	 */
	private Vector<TrackEntry>			marketEntries;
	private String									moduleName			= null;

	// - M A I N S E C T I O N
	public static void main(String[] args) {
		// - The startup and initialization process must be as light as possible to allow all inherited code
		// to be executed instead making a lot of calls.
		MarketHistoryApp.singleton = new MarketHistoryApp(args);
		//		singleton.banner();
		MarketHistoryApp.singleton.execute();
		exit(0);
	}

	public MarketHistoryApp(final String[] args) {
		// INFO The initialization process follows this rules:
		// - The instance is created and this constructor is called.
		// - Log must be initialized and the application banner printed to signal the start of the process.
		// - Parameter processing is the next task. Call the hierarchy to process any common parameters and
		// then process internally all parameters left.
		// - Parameter validations for mandatory parameters and any other parameter processing to generate
		// configuration data from the parameter data such as file reading or parameter concatenation.
		// After this steps the application instance is ready to start. The next step is the initialization that
		// maybe can be included inside this method or moved away if there are functionalities than can be
		// inherithed.
		super(args);

		// - Store the parameters received on this invocation into the instance for method availability.
		parameters = args;
		// - Initialize log and print out the banner
		//		banner();

		// - Process parameters and store them into the instance fields
		processParameters(args, APPLICATIONNAME);
	}

	/**
	 * Main execution method for each command line application. On this application we use the HTMLParser open
	 * source libraries to get the HTML source code of pages parsed.<br>
	 * This application does the next activities in order:
	 * <ul>
	 * <li>Creates a parser for this specific content type of market data pages. Pages come from
	 * <bold>eve-marketdata.com</bold> and represents the HTML content for SELLERS pages.</li>
	 * <li>Processes the content page for an specific and select module</li>
	 * <li>Filter out the appropriate entries from the complete list</li>
	 * <li>Make a report to be used in OpenOffice</li>
	 * </ul>
	 */
	public void execute() {
		Vector<ModuleDescriptor> moduleList = new Vector<ModuleDescriptor>();
		if (null != moduleName)
			moduleList.add(new ModuleDescriptor(moduleName, generateBuyURL(moduleName)));
		else {
			moduleList.add(new ModuleDescriptor("Adaptive Nano Plating II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Adaptive+Nano+Plating+II"));
			moduleList.add(new ModuleDescriptor("Nanofiber Internal Structure II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Nanofiber+Internal+Structure+II"));
			moduleList.add(new ModuleDescriptor("Inertia Stabilizers II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Inertia+Stabilizers+II"));
			moduleList.add(new ModuleDescriptor("Overdrive Injector System II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Overdrive+Injector+System+II"));
			moduleList.add(new ModuleDescriptor("Damage Control II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Damage+Control+II"));
			moduleList.add(new ModuleDescriptor("Expanded Cargohold II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Expanded+Cargohold+II"));
			moduleList.add(new ModuleDescriptor("Gyrostabilizer II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Gyrostabilizer+II"));
			moduleList.add(new ModuleDescriptor("Warp Core Stabilizer II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Warp+Core+Stabilizer+II"));
			moduleList.add(new ModuleDescriptor("Adaptive Invulnerability Field II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Adaptive+Invulnerability+Field+II"));
			moduleList.add(new ModuleDescriptor("Armor EM Hardener II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_id=11642"));
			moduleList.add(new ModuleDescriptor("Armor Explosive Hardener II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_id=11646"));
			moduleList.add(new ModuleDescriptor("Armor Kinetic Hardener II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_id=11644"));
			moduleList.add(new ModuleDescriptor("Armor Thermic Hardener II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_id=11648"));
			moduleList.add(new ModuleDescriptor("Plagioclase Mining Crystal II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Plagioclase+Mining+Crystal+II"));
			moduleList.add(new ModuleDescriptor("Scordite Mining Crystal II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Scordite+Mining+Crystal+II"));
			moduleList.add(new ModuleDescriptor("Prototype Cloaking Device II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Prototype+Cloaking+Device+II"));
			moduleList.add(new ModuleDescriptor("Small Tractor Beam II",
					"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Small+Tractor+Beam+II"));
		}
		executeProcess(moduleList);
	}

	private String generateBuyURL(String moduleName) {
		String escapedName = moduleName.replaceAll(" ", "+");
		return "http://eve-marketdata.com/price_check.php?type=sell&type_name_header=" + escapedName;
		//		return "http://eve-marketdata.com/price_check.php?type=sell&type_name_header=Adaptive+Nano+Plating+II";
	}

	private void executeProcess(Vector<ModuleDescriptor> moduleList) { // Create a single reader to perform all download and parsing operations.
		try {
			org.xml.sax.XMLReader reader;
			reader = org.xml.sax.helpers.XMLReaderFactory.createXMLReader("org.htmlparser.sax.XMLReader");

			// Create out specific parser for this type of content.
			EVEMarketDataParser content = new EVEMarketDataParser();
			reader.setContentHandler(content);
			reader.setErrorHandler(content);
			final Calendar now = TimeZoneAdapter.changeTimeZone(Calendar.getInstance(), "Etc/GMT+1");
			final SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/YYYY HH:mm:ss");
			String timeStamp=formatter.format(now.getTime());

			// Process all of the selected modules one by one and generate the report for each of the iterations.
			Iterator<ModuleDescriptor> mlit = moduleList.iterator();
			while (mlit.hasNext()) {
				// Get the module descriptor to start the processing.
				ModuleDescriptor module = mlit.next();
				String URLDestination = module.getMooduleURL();
				if (null != URLDestination) {
					// Reset the parser contents.
					content.reset();
					reader.parse(URLDestination);
					//					output("\n\tStation\t" + module.getModuleName());
					marketEntries = content.getEntries();
					Vector<String> stationList = new Vector<String>();
					stationList.add("0.9 Sinq Laison - Dodixie");
					stationList.add("0.9 The Forge - Jita");
					stationList.add("0.9 Heimatar - Rens");
					stationList.add("0.5 Metropolis - Hek");
					stationList.add("0.9 Verge Vendor - Alentene");
					stationList.add("1.0 Domain - Amarr");
					Iterator<TrackEntry> meit = marketEntries.iterator();
					while (meit.hasNext()) {
						TrackEntry entry = meit.next();
						// Filtering for only suitable places.
						boolean match = filterStations(entry, stationList);
						if (match) {
							// If this station was already processed the station has to be removed from the matching list so
							// no more entries are detected.
							StringBuffer report = new StringBuffer();
							report.append("ModulePrice:").append(entry.getPrice()).append(" ");
							report.append("ModuleQty:").append(entry.getQty()).append(" ");
							report.append("ModuleName:").append(module.getModuleName()).append(" ");
							report.append("Date:").append(timeStamp);
							//							report.append(module.getModuleName()).append("/").append(entry.getStationName()).append("\t");
							//							report.append(entry.getStationName()).append("\t");
							//							report.append(entry.getPrice()).append("\t");
							//							report.append(entry.getQty());
							System.out.println(report.toString());
							try {
								String writerName = entry.getStationName() + ".txt";
								PrintWriter writer = new PrintWriter(new FileOutputStream(writerName, true), true);
								writer.println(report.toString());
								writer.close();
							} catch (final FileNotFoundException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							stationList.remove(entry.getStationName());
							if (stationList.size() == 0) break;
						}
					}
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void executeBuy() {
		banner();
		Vector<ModuleDescriptor> moduleList = new Vector<ModuleDescriptor>();
		moduleList.add(new ModuleDescriptor("Adaptive Nano Plating II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Adaptive+Nano+Plating+II"));
		moduleList.add(new ModuleDescriptor("Nanofiber Internal Structure II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Nanofiber+Internal+Structure+II"));
		moduleList.add(new ModuleDescriptor("Inertia Stabilizers II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Inertia+Stabilizers+II"));
		moduleList.add(new ModuleDescriptor("Overdrive Injector System II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Overdrive+Injector+System+II"));
		moduleList.add(new ModuleDescriptor("Damage Control II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Damage+Control+II"));
		moduleList.add(new ModuleDescriptor("Expanded Cargohold II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Expanded+Cargohold+II"));
		moduleList.add(new ModuleDescriptor("Gyrostabilizer II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Gyrostabilizer+II"));
		moduleList.add(new ModuleDescriptor("Warp Core Stabilizer II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Warp+Core+Stabilizer+II"));
		moduleList.add(new ModuleDescriptor("Adaptive Invulnerability Field II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Adaptive+Invulnerability+Field+II"));
		moduleList.add(new ModuleDescriptor("Armor EM Hardener II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_id=11642"));
		moduleList.add(new ModuleDescriptor("Armor Explosive Hardener II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_id=11646"));
		moduleList.add(new ModuleDescriptor("Armor Kinetic Hardener II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_id=11644"));
		moduleList.add(new ModuleDescriptor("Armor Thermic Hardener II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_id=11648"));
		moduleList.add(new ModuleDescriptor("Plagioclase Mining Crystal II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Plagioclase+Mining+Crystal+II"));
		moduleList.add(new ModuleDescriptor("Scordite Mining Crystal II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Scordite+Mining+Crystal+II"));
		moduleList.add(new ModuleDescriptor("Prototype Cloaking Device II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Prototype+Cloaking+Device+II"));
		moduleList.add(new ModuleDescriptor("Small Tractor Beam II",
				"http://eve-marketdata.com/price_check.php?type=buy&type_name_header=Small+Tractor+Beam+II"));
		executeProcess(moduleList);
	}

	private boolean filterStations(TrackEntry entry, Vector<String> stationList) {
		Iterator<String> slit = stationList.iterator();
		while (slit.hasNext()) {
			String stationNameMatch = slit.next();
			String station = entry.getStationName();
			if (station.contains(stationNameMatch)) return true;
		}
		return false;
	}

	public void processParameters(final String[] args, final String ApplicationName) {
		for (int i = 0; i < args.length; i++) {
			logger.info("Application argument: args[" + i + "] = " + args[i]);
			// - Test all parameters that start with the character '-'. They are
			// the parameter codes
			if (args[i].startsWith("-")) { //$NON-NLS-1$
				if (args[i].toLowerCase().startsWith("-mod")) {
					// - Get the module name to process
					moduleName = argumentStringValue(args, i);
					continue;
				}
				if (args[i].startsWith("-help")) {
					help();
					exit(0);
				}
				continue;
			}
		}
		// ... Check that required parameters have values.
//		if (null == moduleName) exit(NOMODULE);
	}

	protected double argumentDoubleValue(final String[] args, final int position) {
		// - Get the next argument.
		final String argument = argumentStringValue(args, position);
		final double value = new Double(argument).doubleValue();
		return value;
	}

	protected int argumentIntegerValue(final String[] args, final int position) {
		// - Get the next argument.
		final String argument = argumentStringValue(args, position);
		final int value = new Integer(argument).intValue();
		return value;
	}

	protected String argumentStringValue(final String[] args, final int position) {
		// - Check argument array size before trying to get the argument value
		if (position + 1 < args.length)
			return args[position + 1];
		else {
			// - Exit point 10. There are no enough arguments in the list to find a value.
			exit(NOCONFIG);
		}
		return "";
	}

	private void banner() {
		output(" __  __            _        _  _____               _    _");
		output("|  \\/  | __ _ _ __| | _____| ||_   _| __ __ _  ___| | _(_)_ __   __ _");
		output("| |\\/| |/ _` | '__| |/ / _ \\ __|| || '__/ _` |/ __| |/ / | '_ \\ / _` |");
		output("| |  | | (_| | |  |   <  __/ |_ | || | | (_| | (__|   <| | | | | (_| |");
		output("|_|  |_|\\__,_|_|  |_|\\_\\___|\\__||_||_|  \\__,_|\\___|_|\\_\\_|_| |_|\\__, |");
		output("                                                                |___/");
		output();
		output("VERSION v1.0");
		output();
	}

	private void help() {
		System.out.println("Command API for the RouteCalcualtor:");
		System.out.println("java -classpath routecalculator.jar net.sf.vorg.routecalculator.command.main.RouteCalculator ");
		System.out.println("Allowed parameters:");
		System.out.println("-sta[rt] <lat grade:lat minute> <lon grade:lon minute> or <lat> <lon>");
		System.out.println();
	}
}
 class TimeZoneAdapter {
	// - S T A T I C - S E C T I O N ..........................................................................
	private static Logger	logger	= Logger.getLogger("net.sf.vorg.core.util");

	public static Calendar changeTimeZone(Calendar targetDate, String newTimeZoneID) {
		int localTimeZoneOffset = targetDate.getTimeZone().getOffset(targetDate.getTimeInMillis());
		int gmtTimeZoneOffset = TimeZone.getTimeZone(newTimeZoneID).getOffset(targetDate.getTimeInMillis());
		int savings = targetDate.getTimeZone().getDSTSavings();
		int localDisplacement = localTimeZoneOffset * -1 + gmtTimeZoneOffset * -1;
		targetDate.add(Calendar.MILLISECOND, localTimeZoneOffset * -1);
		targetDate.add(Calendar.MILLISECOND, gmtTimeZoneOffset * -1);
		targetDate.add(Calendar.MILLISECOND, savings);
		return targetDate;
	}

	// - F I E L D - S E C T I O N ............................................................................

	// - C O N S T R U C T O R - S E C T I O N ................................................................
	public TimeZoneAdapter() {
	}

	// - M E T H O D - S E C T I O N ..........................................................................
}
